﻿namespace In66.Net.Share.Authentication.Basic
{
    /// <summary>
    /// Basic验证(认证)服务
    /// </summary>
    public class BasicAuthenticationHandler : AuthenticationHandler<BasicSchemeOptions>
    {
        private readonly Microsoft.Extensions.Logging.ILogger _logger;
        public BasicAuthenticationHandler(
            IOptionsMonitor<BasicSchemeOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock
            ) : base(options, logger, encoder, clock)
        {
            _logger = logger.CreateLogger<BasicAuthenticationHandler>();

        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            AuthenticateResult authResult;
            try
            {
                var authHeader = Request.Headers["Authorization"].ToString();

                if (Context?.GetEndpoint()?.Metadata.GetMetadata<IAllowAnonymous>() is not null)
                {
                    return await Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(), BasicDefaults.AuthenticationScheme)));
                }

                if (authHeader is not null && authHeader.StartsWith(BasicDefaults.AuthenticationScheme))
                {
                    var startIndex = BasicDefaults.AuthenticationScheme.Length + 1;
                    var token = authHeader[startIndex..].Trim();
                    if (token.IsNullOrWhiteSpace())
                    {
                        Response.StatusCode = (int)HttpStatusCode.Forbidden;
                        authResult = AuthenticateResult.Fail("Invalid Authorization Token");
                        return await Task.FromResult(authResult);
                    }

                    var validatedResult = BasicTokenValidator.UnPackFromBase64(token);

                    if (validatedResult.IsSuccessful)
                    {
                        var claims = new[] {
                        new Claim(BasicDefaults.NameId, validatedResult.AppId)
                        , new Claim(BasicDefaults.UniqueName, validatedResult.UserName)
                        , new Claim(BasicDefaults.Name, validatedResult.UserName)
                    };

                        var identity = new ClaimsIdentity(claims, BasicDefaults.AuthenticationScheme);
                        var claimsPrincipal = new ClaimsPrincipal(identity);
                        authResult = AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, BasicDefaults.AuthenticationScheme));
                        var validatedContext = new BasicTokenValidatedContext(Context, Scheme, Options)
                        {
                            Principal = claimsPrincipal
                        };

                        await Options.Events.OnTokenValidated.Invoke(validatedContext);

                        return await Task.FromResult(authResult);
                    }

                    Response.StatusCode = (int)HttpStatusCode.Forbidden;
                    authResult = AuthenticateResult.Fail("Invalid Authorization Token");
                    return await Task.FromResult(authResult);
                }
                Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                authResult = AuthenticateResult.Fail("Invalid Authorization Header");
                return await Task.FromResult(authResult);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                authResult = AuthenticateResult.Fail("Invalid Authorization Header");
                return await Task.FromResult(authResult);
            }
        }
    }
}
